﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.Web;
using WcfGeebaServer;
using WcfGeebaServer.ContentManage;
using WcfGeebaServer.DBDAL;
using WcfGeebaServer.Logging;
using WcfGeebaServer.Policies;
using WcfGeebaServer.Users;
using WcfGeebaServer.Utils;
using AcceptnaceTests;
using ServerAdapter;

namespace AcceptanceTests
{
    [TestClass]
    public class TestServer
    {
        private static Service _server = new Service();
        private static string _adminPassword;

        public TestServer(){
            Data.ClearDB();
            GPolicy policy = new GPolicy();

            _adminPassword = EncDec.Encrypt(TestUtils.GetAdminPassword(), EncDec.getServerKey());
            _server.init(TestUtils.GetAdminUsername(), _adminPassword, policy);
            //InitForumTest();
        }

        [TestMethod]
        public void InitForumTest()
        {
            GPolicy policy = new GPolicy();
            Assert.IsTrue(_server.init("admin1", _adminPassword, policy));
            Assert.AreEqual(1, Data.members.Count);
            User user = _server.entry();

            Member member = _server.login(user, "admin1", _adminPassword);
            Assert.IsNotNull(member);
            Assert.AreEqual(UserType.Admin, member.UserType);
        }

        [TestMethod]
        public void EntranceTest()
        {
            User user = _server.entry();
            Assert.IsNotNull(user);

            for (int i = 0; i < 1000; i++)
            {
                user = _server.entry();
                Assert.IsNotNull(user);
            }
        }

        [TestMethod]
        public void NewRegistrationTest()
        {
            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();

            Assert.IsTrue(_server.register(username, pass));
        }

        [TestMethod]
        public void ExistingRegistrationTest()
        {

            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            Assert.IsTrue(_server.register(username, pass));
            Assert.IsFalse(_server.register(username, pass));
        }

        [TestMethod]
        public void LoginTest()
        {

            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();

            try
            {
                //not registered
                Assert.IsNull(_server.login(user, username, pass));
            }
            catch
            {
                Assert.IsTrue(true);
            }

            Assert.IsTrue(_server.register(username, pass));
            Assert.IsNotNull(_server.login(user, username, pass));
            try
            {
                //already logged in
                Assert.IsNotNull(_server.login(user, username, pass));
                Assert.IsFalse(false);
            }
            catch
            {
                Assert.IsTrue(true);
            }

        }

        [TestMethod]
        public void LogoutTest()
        {

            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            Assert.IsTrue(_server.register(username, pass));

            Member member = _server.login(user, username, pass);
            Assert.IsNotNull(member);
            Assert.AreEqual(member.UserType, UserType.Member);

            user = _server.logout(member.Username);
            Assert.AreEqual(user.UserType, UserType.Guest);
        }

        [TestMethod]
        public void GuestViewSubForumsTest()
        {
            _addSubForumByAdmin();
            User user = _server.entry();
            Assert.IsNotNull(_server.getSubForums());
        }

        [TestMethod]
        public void MemberViewSubForumsTest()
        {
            _addSubForumByAdmin();
            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            Assert.IsTrue(_server.register(username, pass));
            Member member = _server.login(user, username, pass);
            Assert.IsNotNull(_server.getSubForums());
        }

        [TestMethod]
        public void PublishMessageByMemberTest()
        {
            _addSubForumByAdmin();
            User user = _server.entry();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            Assert.IsTrue(_server.register(username, pass));
            Member member = _server.login(user, username, pass);
            List<GSubForum> subforums = _server.getSubForums();
            Assert.IsNotNull(subforums);
            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            Assert.IsTrue(_server.publish(member, subforums.ElementAt(0).Topic, thread) > 0);
        }

        [TestMethod]
        public void PublishMessageByGuestTest()
        {

            User user = _server.entry();
            string pass = TestUtils.GetPassword();
            Member member = new Member(user.Username, pass, true);
            _addSubForumByAdmin();
            List<GSubForum> subforums = _server.getSubForums();
            Assert.IsNotNull(subforums);
            try
            {
                GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
                _server.publish(member, subforums.ElementAt(0).Topic, thread);
                Assert.Fail("publish message by guest.");
            }
            catch
            {
                Assert.IsTrue(true);
            }
        }

        [TestMethod]
        public void ViewThreads()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();

            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            _addSubForumByAdmin();
            GSubForum sf = _server.getSubForums().ElementAt(0);
            GThread new_thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            int pgt = _server.publish(member, sf.Topic, new_thread);
            Assert.IsTrue(pgt > 0);
            List<GThread> threads = _server.getThreads(sf);
            GThread result = threads.Find(
                delegate(GThread thread)
                {
                    return (thread.Subject.Equals(TestUtils.GetCurrentSubject()) && thread.publishedBy.Equals(member));
                }
            );
            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void AddSubForumByAdmin()
        {
            this._addSubForumByAdmin();
        }

        private string _addSubForumByAdmin()
        {
            string topic = TestUtils.GetNextTopic();
            Member member = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            Assert.IsTrue(_server.addSubForum(member, topic, TestUtils.GetAdminUsername()));
            return topic;
        }

        [TestMethod]
        public void AddSubForumByNotAdmin()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            try
            {
                _server.addSubForum(member, TestUtils.GetNextTopic(), TestUtils.GetAdminUsername());
                Assert.Fail("ERROR: added sub forum by not admin!");
            }
            catch
            {
                Assert.IsTrue(true);
            }
        }

        [TestMethod]
        public void RemoveSubForumByAdmin()
        {
            string topic = this._addSubForumByAdmin();
            Member member = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            _server.removeSubForum(member, topic);
        }

        [TestMethod]
        public void RemoveSubForumByNotAdmin()
        {
            string topic = this._addSubForumByAdmin();
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            Member member = _server.login(_server.entry(), username, pass);
            try
            {
                _server.removeSubForum(member, topic);
                Assert.Fail("remove sub forum by admin.");
            }
            catch
            {
                Assert.IsTrue(true);
            }

        }

        [TestMethod]
        public void GetMemberThreadCountByAdmin()
        {
            Member member = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(member, topic, TestUtils.GetAdminUsername());
            int before = _server.getMemberThreadCount(member, TestUtils.GetAdminUsername());
            Assert.IsTrue(before >= 0);
            _server.publish(member, topic, new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member));
            Assert.IsTrue(_server.getMemberThreadCount(member, TestUtils.GetAdminUsername()) - before == 1);
        }

        [TestMethod]
        public void GetMemberThreadCountByNotAdmin()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            string topic = TestUtils.GetNextTopic();
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            try
            {
                _server.getMemberThreadCount(member, username);
                Assert.Fail("get member thread count by not admin.");
            }
            catch
            {
                Assert.IsTrue(true);
            }
        }

        [TestMethod]
        public void ChangePassword()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);

            string newPass = TestUtils.GetNewPassword();
            _server.changePassword(member, pass, newPass);
            Member newMember = _server.login(_server.entry(), username, newPass);
            Assert.IsNotNull(newMember);
        }

        [TestMethod]
        public void RemoveThreadByPublisher()
        {
            string topic = TestUtils.GetNextTopic();
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            int id = _server.publish(member, topic, new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member));

            Assert.IsTrue(_server.removeThread(member, topic, id));
        }

        [TestMethod]
        public void RemoveThreadByNotPublisher()
        {
            string topic = TestUtils.GetNextTopic();
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            int id = _server.publish(member, topic, new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member));

            string username1 = TestUtils.GetNextUsername();
            string pass1 = TestUtils.GetPassword();
            _server.register(username1, pass1);
            Member notPublisher = _server.login(_server.entry(), username1, pass1);
            try
            {
                _server.removeThread(notPublisher, topic, id);
                Assert.Fail("remove thread not by publisher.");
            }
            catch
            {
                Assert.IsTrue(true);
            }
        }

        [TestMethod]
        public void AddModerator()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            bool forumAdd = _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            for (int i = 0; i < 5; i++)
            {
                _server.publish(member, topic, new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member));
            }
            Assert.IsTrue(_server.addModerator(admin, topic, username));
        }

        [TestMethod]
        public void ReplaceModerator()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            bool forumAdd = _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            for (int i = 0; i < 5; i++)
            {
                _server.publish(member, topic, new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member));
            }
            Assert.IsTrue(_server.replaceModerator(admin, topic, TestUtils.GetAdminUsername(), username));
        }

        [TestMethod]
        public void RemoveModerator()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            bool forumAdd = _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            for (int i = 0; i < 5; i++)
            {
                GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
                _server.publish(member, topic, thread);
            }
            _server.addModerator(admin, topic, username);

            Assert.IsTrue(_server.removeModerator(admin, topic, TestUtils.GetAdminUsername()));
        }

        [TestMethod]
        public void GetThreadCount()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            Assert.AreEqual(0, _server.getThreadCount(admin, topic));

            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin);
            _server.publish(admin, topic, thread);
            Assert.AreEqual(1, _server.getThreadCount(admin, topic));
        }

        [TestMethod]
        public void CommentThread()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());

            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin);
            int thId = _server.publish(admin, topic, thread);

            GPost post = new GPost(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin, null);
            Assert.IsTrue(_server.comment(admin, post, topic, thId) > 0);
        }

        [TestMethod]
        public void CommentPost()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin);
            int thId = _server.publish(admin, topic, thread);
            GPost post1 = new GPost(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin, null);
            int pId = _server.comment(admin, post1, topic, thId);
            GPost post2 = new GPost(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin, null);
            Assert.IsTrue(_server.comment(admin, post2, topic, pId) > 0);
        }

        [TestMethod]
        public void EditContent()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            GThread newThread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin);
            int thId = _server.publish(admin, topic, newThread);
            Assert.IsTrue(_server.editContent(admin, topic, thId, TestUtils.GetNextContent()));
        }

        [TestMethod]
        public void BumpThread()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());
            GThread newThread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), admin);
            int thId = _server.publish(admin, topic, newThread);
            Assert.IsTrue(_server.bumpThread(admin, topic, thId));
        }

        [TestMethod]
        public void SetInactiveMember()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            Assert.IsTrue(_server.SetActiveMember(member, false));
            member = _server.login(_server.logout(username), username, pass);
            Assert.IsFalse(member.IsActive);
        }

        [TestMethod]
        public void SetInactiveThenActiveMember()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);
            Assert.IsTrue(_server.SetActiveMember(member, false));
            member = _server.login(_server.logout(username), username, pass);
            Assert.IsFalse(member.IsActive);

            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());

            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            Assert.IsTrue(_server.publish(member, topic, thread) < 0);

            Assert.IsTrue(_server.SetActiveMember(member, true));

            member = _server.login(_server.logout(username), username, pass);
            Assert.IsTrue(member.IsActive);

            GThread thread2 = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            Assert.IsTrue(_server.publish(member, topic, thread2) >= 0);
        }

        [TestMethod]
        public void AdminTryToChangeMessageContent()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);

            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());

            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            int threadID = _server.publish(member, topic, thread);

            Assert.IsTrue(_server.editContent(member, topic, threadID, "new content by member"));
            Assert.IsFalse(_server.editContent(admin, topic, threadID, "new content by admin"));
        }

        [TestMethod]
        public void ModeratorTryToChangeMessageContent()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);

            string username2 = TestUtils.GetNextUsername();
            string pass2 = TestUtils.GetPassword();
            _server.register(username2, pass2);
            Member moderator = _server.login(_server.entry(), username2, pass2);

            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, username2);

            Assert.IsTrue(_server.getModerators(admin, topic).Contains(moderator));

            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            int threadID = _server.publish(member, topic, thread);

            Assert.IsTrue(_server.editContent(member, topic, threadID, "new content by member"));
            Assert.IsFalse(_server.editContent(moderator, topic, threadID, "new content by moderator"));
        }

        [TestMethod]
        public void BanUser()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);

            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
             string topic = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic, TestUtils.GetAdminUsername());

            Assert.IsFalse(_server.BanMember(admin, username));
            member = _server.login(_server.logout(username), username, pass);
            Assert.IsFalse(member.IsBanned);

            _server.SetActiveMember(member, false);
            GThread thread = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            Assert.IsTrue(_server.publish(member, topic, thread) < 0);
            Assert.IsTrue(_server.BanMember(admin, username));

            member = _server.login(_server.logout(username), username, pass);
            Assert.IsNull(member);
        }

        [TestMethod]
        public void SearchForMessageByContent()
        {
            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic1 = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic1, TestUtils.GetAdminUsername());
            string content = "special content for test 12345";
            GThread thread1 = new GThread(TestUtils.GetNextSubject(), content, admin);
            int threadID1 = _server.publish(admin, topic1, thread1);
            string topic2 = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic2, TestUtils.GetAdminUsername());
            GThread thread2 = new GThread(TestUtils.GetNextSubject(), content, admin);
            int threadID2 = _server.publish(admin, topic2, thread2);

            List<GThread> results = _server.searchByContent(content);
            Assert.IsTrue((results[0].Id == threadID1) || (results[0].Id == threadID2));
            Assert.IsTrue((results[1].Id == threadID1) || (results[1].Id == threadID2));
            Assert.IsTrue(results.Count == 2);

            results = _server.searchByContent(content.Substring(10));
            Assert.IsTrue((results[0].Id == threadID1) || (results[0].Id == threadID2));
            Assert.IsTrue((results[1].Id == threadID1) || (results[1].Id == threadID2));
            Assert.IsTrue(results.Count == 2);
        }

        [TestMethod]
        public void SearchForMessageByPublisher()
        {
            string username = "specialUserName";
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            Member member = _server.login(_server.entry(), username, pass);

            Member admin = _server.login(_server.entry(), TestUtils.GetAdminUsername(), _adminPassword);
            string topic1 = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic1, TestUtils.GetAdminUsername());
            GThread thread1 = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            int threadID1 = _server.publish(member, topic1, thread1);
            string topic2 = TestUtils.GetNextTopic();
            _server.addSubForum(admin, topic2, TestUtils.GetAdminUsername());
            GThread thread2 = new GThread(TestUtils.GetNextSubject(), TestUtils.GetNextContent(), member);
            int threadID2 = _server.publish(member, topic2, thread2);
            
            List<GThread> results = _server.searchByUser(username);
            Assert.IsTrue((results[0].Id == threadID1) || (results[0].Id == threadID2));
            Assert.IsTrue((results[1].Id == threadID1) || (results[1].Id == threadID2));
            Assert.IsTrue(results.Count == 2);
        }


        [TestMethod]
        public void ShowNumberOfConnectedUsers()
        {
            string username = TestUtils.GetNextUsername();
            string pass = TestUtils.GetPassword();
            _server.register(username, pass);
            int numOfUSers = _server.getConnectedMembersCount();
            Member member = _server.login(_server.entry(), username, pass);
            Assert.IsTrue(_server.getConnectedMembersCount() == numOfUSers + 1);
            _server.logout(username);
            Assert.IsTrue(_server.getConnectedMembersCount() == numOfUSers);
        }
    }
}
